#include "task.hpp"
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <iostream>
#include <stdlib.h>
#include <string>
#include <vector>
#include <sys/wait.h>
const int processnum = 10; // 创造进程的个数
std::vector<task_t> tasks; // 任务表

class channel // 连通管道的两端的描述信息
{
public:
    channel(int cmdfd, int childid, const std::string &processname)
        : _cmdfd(cmdfd), _childid(childid), _processname(processname)
    {
    }

public:
    int _cmdfd;               // 发送任务的文件描述符
    pid_t _childid;           // 子进程的PID
    std::string _processname; // 子进程的名字 -- 方便我们打印日志
};

void child_work()
{
    while (true)
    {
        int command = 0;
        int n = read(0, &command, sizeof(command)); // 父进程不给子进程发送数据,read阻塞等待

        if (n == sizeof(command))
        {
            // 执行对应的任务
            std::cout << "子进程的 id:  " << getpid() << "  command:  " << command << std::endl;
            if (command >= 0 && command < tasks.size())
            {
                tasks[command]();
            }
        }
        if (n == 0)
        {
            break;
        }
    }
}

void InitProcess(std::vector<channel> *channels)
{
    std::vector<int> oldfds;
    for (int i = 0; i < processnum; i++)
    {

        int pipeid[2]; // 创造管道，子进程继承父类的 文件描述符等  , 0是读， 1是写
        int n = pipe(pipeid);
        assert(!n);

        pid_t id = fork();

        if (id == 0) // 子进程
        {
            std::cout << "child: " << getpid() << " close history fd: ";
            // 子进程删除对其它管道的写入通道
            for (auto fd : oldfds)
            {
                std::cout << fd << " ";
                close(fd);
            }
            std::cout << "\n";

            close(pipeid[1]);

            dup2(pipeid[0], 0); // 从显示器里读
            close(pipeid[0]);
            child_work(); // 子进程的工作

            std::cout << "child process : " << getpid() << " quit" << std::endl;

            exit(0);
        }
        // id > 0 ,父进程
        close(pipeid[0]);

        // 添加channel
        std::string name = "process-" + std::to_string(i);
        channels->push_back(channel(pipeid[1], id, name));
        oldfds.push_back(pipeid[1]);
        sleep(1);
    }
}

void Menu()
{
    std::cout << "################################################" << std::endl;
    std::cout << "# 1. 增加             2. 删除        ############" << std::endl;
    std::cout << "# 3. 修改             4. 查找        ############" << std::endl;
    std::cout << "#                     0. 退出        ############" << std::endl;
    std::cout << "#################################################" << std::endl;
}

void SendTask(const std::vector<channel> &channels)
{
    int which = 0;

    while (true)
    {
        // 1.选择要执行的任务
        int select = 0;
        Menu();
        std::cout << "请输入你想要执行的任务:";
        std::cin >> select;

        if (select <= 0 || select >= 5)
            break;

        int command = select - 1;

        // 2.不同的子进程执行任务
        std::cout << "父进程委派的任务是: " << " command: " << command << " already sendto " << channels[which]._childid << " process name: "
                  << channels[which]._processname << std::endl;

        // 3.发生任务给子进程
        write(channels[which]._cmdfd, &command, sizeof(command));

        which++;
        which %= channels.size();
        sleep(1);
    }
}

void DeleteProcess(const std::vector<channel> &channels)
{
    for (const auto &c : channels)
    {
        close(c._cmdfd);
        waitpid(c._childid, nullptr, 0);
    }
}
int main()
{
    // 加载任务
    LoadTask(&tasks);

    // 组织每个管道的描述信息
    std::vector<channel> channels;

    // 初始化创造进程，以及管道的搭建
    InitProcess(&channels);

    // 传达的任务
    SendTask(channels);

    // 清理进程
    DeleteProcess(channels);

    return 0;
}
